Skip to content

Conversation

@Leon-hk
Copy link

@Leon-hk Leon-hk commented Jan 7, 2026

What this PR does / why we need it:

  • For the still unmerged reproducibility checker, I've written a format_diff.py script which generates a readme report for the workflow run
  • This script manually parsed the flavors directory and created feature trees. But this can also be way easier and more reliable done using the python-gardenlinux-lib
  • This PR ports the readme generator to the python-gardenlinux-lib in order to clean up the workflows directory, to use features of the library and to be able to test the output with simple unit tests

@codecov
Copy link

codecov bot commented Jan 8, 2026

Codecov Report

❌ Patch coverage is 86.84211% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.15%. Comparing base (95a3985) to head (9abe888).

Files with missing lines Patch % Lines
.../gardenlinux/features/difference_formatter_main.py 0.00% 23 Missing ⚠️
src/gardenlinux/features/difference_formatter.py 98.80% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #294      +/-   ##
==========================================
- Coverage   91.55%   91.15%   -0.40%     
==========================================
  Files          42       44       +2     
  Lines        2083     2273     +190     
==========================================
+ Hits         1907     2072     +165     
- Misses        176      201      +25     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@NotTheEvilOne NotTheEvilOne self-requested a review January 17, 2026 09:48
commit: str


class Formatter(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File name and class name should be the same. Furthermore the class name should indicate what it formats or into which format. I guess MarkdownFormatter might be most suitable as we do not intend to support multiple output formats anyway.

To not loose what it formats a package called gardenlinux.features.reproducibility might be suitable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file mixes output and parsing logic. Separating the functionality might allow reusability.

diff_dir = pathlib.Path(gardenlinux_root).joinpath(diff_dir)

self._all = set()
self._flavors = os.listdir(diff_dir)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable indicates a different content then what it contains. Based on GardenLinux naming convention a flavor is a specific set of features as a string. E.g. gcp-gardener_prod_trustedboot resulting in a GardenLinux canonical name if appended with the CPU architecture, version and commit.

This variable contains files produced during one build if I understand it correctly.


remove_arch = re.compile("(-arm64|-amd64)$")

def __init__(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor does way too much. Usually a constructor should only set-up an instance. If needed it might call class methods to increase readability.


self._parser = Parser(gardenlinux_root, feature_dir_name, logger)
if gardenlinux_root is None:
gardenlinux_root = self._parser._GARDENLINUX_ROOT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing private members are discouraged. If needed Parser can be extended to provide the directory information used at an instance of it.

:since: 1.0.0
"""

if len(items) <= 10:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic numbers - please use a constant for the limit :)

found.update(fnd)
s += " " + st.replace("\n", "\n ") + "\n"
# Remove last linebreak as the last line can contain spaces
return "\n".join(s.split("\n")[:-1]), found
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't rstrip() be more appropriate here?

first = True
tree = None
for flavor in flavors:
if not flavor.startswith("bare-"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hidden magic is always a request for hard to debug issues later on. Please add # @TODO comments where applicable.

"""

with open(
self._parser._feature_base_dir.joinpath(f"{node}/info.yaml"), "r"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already accessed the private root directory variable from Parser. Best practice (if not otherwise possible) would be to store it in this instance in __init__() for later reuse.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect gl-diff to at least additionally produce the diff files formatted here as well. Based on if that would be feasible the file name should either indicate it's handling flavor build differential content or it's only parsing and providing output for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants